package com.ethink.platform.util;

import com.ethink.framework.common.util.JacksonUtils;
import com.ethink.platform.properties.PlatformJackyunProperties;
import com.ethink.platform.util.model.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 吉客云开放平台工具类
 *
 * @Author: lzy
 * @Date: Created in 2022/11/23 10:44
 * ModifiedBy:
 * Version:
 */
@Slf4j
@Component
public class JackyunUtils {
    @Autowired
    private PlatformJackyunProperties jackyunProperties;

    private static JackyunUtils jackyunUtils;

    private static final String OMS_TRADE_FULL_INFO_GET_DEFAULT_FIELDS = "tradeNo,checkTotal,otherFee,chargeCurrency," +
            "accountName,warehouseId,payType,payNo,sellerMemo,buyerMemo,appendMemo,tradeFrom,warehouseCode,register," +
            "seller,auditor,reviewer,estimateWeight,packageWeight,customerName,tradeCount,goodsTypeCount,freezeReason," +
            "abnormalDescription,isDelete,onlineTradeNo,goodslist,gmtCreate,gmtModified,stockoutNo,confirmTime,departName," +
            "lastShipTime,payStatus,chargeCurrencyCode,chargeExchangeRate,tradeStatus,grossProfit,estimateVolume," +
            "customerTypeName,customerGradeName,customerTags,customerCode,customerDiscount,tradeTime,country,state,city," +
            "district,town,zip,payTime,countryCode,cityCode,invoiceType,payerName,payerRegno,payerBankAccount,auditTime," +
            "invoiceNo,invoiceCode,invoiceStatus,payerBankName,reviewTime,customerTotalFee,customerDiscountFee,notifyPickTime," +
            "consignTime,orderNo,customerPostFee,shopId,shopName,customerPayment,companyName,isBillCheck,warehouseName," +
            "logisticName,tradeId,logisticType,mainPostid,tradeType,totalFee,taxFee,receivedPostFee,discountFee,payment," +
            "couponFee,receivedTotal,postFee,shopCode,completeTime,signingTime,shopTypeCode,flagIds,flagNames,sysFlagIds," +
            "goodsDetail.goodsNo,goodsDetail.goodsName,goodsDetail.specName,goodsDetail.barcode,goodsDetail.sellCount," +
            "goodsDetail.unit,goodsDetail.sellPrice,goodsDetail.sellTotal,goodsDetail.cost,goodsDetail.discountTotal," +
            "goodsDetail.discountPoint,goodsDetail.taxFee,goodsDetail.shareFavourableFee,goodsDetail.estimateWeight," +
            "goodsDetail.goodsMemo,goodsDetail.cateName,goodsDetail.brandName,goodsDetail.goodsTags,goodsDetail.isFit," +
            "goodsDetail.isGift,goodsDetail.discountFee,goodsDetail.taxRate,goodsDetail.estimateGoodsVolume,goodsDetail.isPresell," +
            "goodsDetail.customerPrice,goodsDetail.customerTotal,goodsDetail.tradeGoodsNo,goodsDetail.tradeGoodsName," +
            "goodsDetail.tradeGoodsSpec,goodsDetail.sourceTradeNo,goodsDetail.sourceSubtradeNo,goodsDetail.platCode," +
            "goodsDetail.platGoodsId,goodsDetail.subTradeId,goodsDetail.isPlatGift,goodsDelivery.subTradeId,goodsDelivery.tradeId," +
            "goodsDelivery.goodsId,goodsDelivery.sendCount,goodsDelivery.batchNo,goodsDelivery.id,tradeOrderPayList.chargeType";

    @PostConstruct
    public void init() {
        jackyunUtils = this;
        jackyunUtils.jackyunProperties = this.jackyunProperties;
    }

    /**
     * 销售单查询
     *
     * @param request
     * @return
     */
    public static JackyunOmsTradeFullInfoResponse omsTradeFullInfoGet(JackyunOmsTradeFullInfoRequest request) {
        if (StringUtils.isBlank(request.getFields())) {
            request.setFields(OMS_TRADE_FULL_INFO_GET_DEFAULT_FIELDS);
        }
        return sendRequest("oms.trade.fullinfoget", request, new ParameterizedTypeReference<JackyunOpenapiResponse<JackyunOmsTradeFullInfoResponse>>(){});
    }

    /**
     * 分页查询网店售后单
     *
     * @param request
     * @return
     */
    public static JackyunOmsBusinessRefundListResponse omsBusinessRefundList(JackyunOmsBusinessRefundListRequest request) {
        String resultDateJson = sendRequest("omsapi-business.refund.listRefund", request, new ParameterizedTypeReference<JackyunOpenapiResponse<String>>(){});
        return JacksonUtils.toObj(resultDateJson, JackyunOmsBusinessRefundListResponse.class);
    }

    /**
     * 发起HTTP请求
     *
     * @param method 接口名
     * @param request
     * @param typeReference
     * @param <R>
     * @param <S>
     * @return
     */
    private static <R, S> S sendRequest(String method, R request, ParameterizedTypeReference<JackyunOpenapiResponse<S>> typeReference) {
        // 请求公共参数
        String bizContent = JacksonUtils.toJson(request);
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
        params.add("method", method);
        params.add("appkey", jackyunUtils.jackyunProperties.getOpenapiAppKey());
        params.add("version", "v1.0");
        params.add("contenttype", "json");
        params.add("timestamp", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        params.add("bizcontent", bizContent);
        params.add("contextid", "");

        Map<String, Object> signParams = new HashMap<>();
        params.forEach((key, value) -> {
            signParams.put(key, value.get(0));
        });
        params.add("sign", generateSign(signParams));

        log.info("吉客云开放平台接口请求业务参数：{}，{}", method, bizContent);
        // 请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("application/x-www-form-urlencoded; charset=UTF-8"));
        // 请求对象
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(params, headers);
        try {
            // 发起请求
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<JackyunOpenapiResponse<S>> response = restTemplate.exchange(jackyunUtils.jackyunProperties.getOpenapiUrl(), HttpMethod.POST, requestEntity, typeReference);
            if (response.getStatusCode() == HttpStatus.OK) {
                // HTTP请求成功
                JackyunOpenapiResponse<S> responseBody = response.getBody();
                log.info("吉客云开放平台接口响应结果：{}，{}", method, responseBody);
                if (responseBody == null) {
                    return null;
                }
                if (responseBody.getCode() == null) {
                    return null;
                }
                if (responseBody.getCode().equals(200)) {
                    // 业务成功
                    return responseBody.getResult().getData();
                } else {
                    // 业务失败
                    return null;
                }
            } else {
                return null;
            }
        } catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 生成签名结果
     *
     * @param signParams
     * @return
     */
    private static String generateSign(Map<String, Object> signParams) {
        Set<String> keySet = signParams.keySet();
        int keySetSize = keySet.size();
        if (keySetSize <= 0) return "";
        String[] keyArray = keySet.toArray(new String[keySetSize]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder(jackyunUtils.jackyunProperties.getOpenapiAppSecret());
        for (String k : keyArray) {
            if (k.equals("sign") || k.equals("contextid")) {
                continue;
            }
            sb.append(k).append(signParams.get(k));
        }
        sb.append(jackyunUtils.jackyunProperties.getOpenapiAppSecret());

        String sign = "";
        try {
            sign = DigestUtils.md5DigestAsHex(sb.toString().toLowerCase().getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sign;
    }
}
